package com.seanchenxi.gwt.wordpress.json.service.impl;

import java.util.ArrayList;
import java.util.Date;

import com.google.gwt.core.client.GWT;
import com.google.gwt.i18n.client.DateTimeFormat;
import com.google.gwt.jsonp.client.JsonpRequestBuilder;
import com.google.gwt.user.client.rpc.AsyncCallback;
import com.seanchenxi.gwt.wordpress.json.service.WordPressJsonServiceAsync;
import com.seanchenxi.gwt.wordpress.json.service.util.JsonConstant;
import com.seanchenxi.gwt.wordpress.json.service.model.Author;
import com.seanchenxi.gwt.wordpress.json.service.model.Category;
import com.seanchenxi.gwt.wordpress.json.service.model.DateIndex;
import com.seanchenxi.gwt.wordpress.json.service.model.Page;
import com.seanchenxi.gwt.wordpress.json.service.model.Post;
import com.seanchenxi.gwt.wordpress.json.service.model.PostType;
import com.seanchenxi.gwt.wordpress.json.service.model.Tag;
import com.seanchenxi.gwt.wordpress.json.service.response.JsonPageCallback;
import com.seanchenxi.gwt.wordpress.json.service.response.JsonPostCallback;
import com.seanchenxi.gwt.wordpress.json.service.response.JsonPostListCallback;

public class WordPressJsonServiceAsyncImpl implements WordPressJsonServiceAsync {

	final static String START = "?";
	final static String AND = "&";
	final static String SLASH = "/";
	final static String EQUAL = "=";
	final static DateTimeFormat dateFormat = DateTimeFormat
			.getFormat("yyy-MM-d");

	private String jsonPath;
	private JsonpRequestBuilder builder;
	 
	public WordPressJsonServiceAsyncImpl(String jsonPath) {
		setJsonPath(jsonPath);
		setBuilder(new JsonpRequestBuilder());
	}

	public String getJsonPath() {
		return jsonPath;
	}

	public void setJsonPath(String jsonPath) {
		this.jsonPath = jsonPath;
		assert this.jsonPath != null;
	}

	public JsonpRequestBuilder getBuilder() {
		return builder;
	}

	public void setBuilder(JsonpRequestBuilder builder) {
		this.builder = builder;
		assert this.builder != null;
	}

	@Override
	public void getPost(int postId, final AsyncCallback<Post> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetPost());
		url = setParameter(url, "id", postId);
		GWT.log("[WordPressJsonServiceAsyncImpl] getPost: " + url);
		getBuilder().requestObject(url, new JsonPostCallback(callback));
	}

	@Override
	public void getPost(String postSlug, AsyncCallback<Post> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetPost());
		url = setParameter(url, "slug", postSlug);
		GWT.log("[WordPressJsonServiceAsyncImpl] getPost: " + url);
		getBuilder().requestObject(url, new JsonPostCallback(callback));
	}

	@Override
	public void getPage(int pageId, AsyncCallback<Page> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetPage());
		url = setParameter(url, "id", pageId);
		GWT.log("[WordPressJsonServiceAsyncImpl] getPage: " + url);
		getBuilder().requestObject(url, new JsonPageCallback(callback));
	}

	@Override
	public void getPage(String pageSlug, AsyncCallback<Page> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetPage());
		url = setParameter(url, "slug", pageSlug);
		GWT.log("[WordPressJsonServiceAsyncImpl] getPage: " + url);
		getBuilder().requestObject(url, new JsonPageCallback(callback));
	}

	@Override
	public void getRecentPosts(AsyncCallback<ArrayList<Post>> callback) {
		getRecentPosts(-1, -1, null, callback);
	}

	@Override
	public void getRecentPosts(int offset, int size, PostType type,
			AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetRecentPosts());
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getRecentPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getDatePosts(Date date, AsyncCallback<ArrayList<Post>> callback) {
		getDatePosts(date, null, -1, -1, callback);
	}

	@Override
	public void getDatePosts(Date date, PostType type, int offset, int size,
			AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetDatePosts());
		url = setParameter(url, "date", date);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getDatePosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getCategoryPosts(int categoryId,
			AsyncCallback<ArrayList<Post>> callback) {
		getCategoryPosts(categoryId, null, -1, -1, callback);
	}

	@Override
	public void getCategoryPosts(String categorySlug,
			AsyncCallback<ArrayList<Post>> callback) {
		getCategoryPosts(categorySlug, null, -1, -1, callback);
	}

	@Override
	public void getCategoryPosts(int categoryId, PostType type, int offset,
			int size, AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetCategoryPosts());
		url = setParameter(url, "id", categoryId);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getCategoryPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getCategoryPosts(String categorySlug, PostType type,
			int offset, int size, AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetCategoryPosts());
		url = setParameter(url, "slug", categorySlug);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getCategoryPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getTagPosts(int tagId, AsyncCallback<ArrayList<Post>> callback) {
		getTagPosts(tagId, null, -1, -1, callback);
	}

	@Override
	public void getTagPosts(String tagSlug,
			AsyncCallback<ArrayList<Post>> callback) {
		getTagPosts(tagSlug, null, -1, -1, callback);
	}

	@Override
	public void getTagPosts(int tagId, PostType type, int offset, int size,
			AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetTagPosts());
		url = setParameter(url, "id", tagId);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getTagPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getTagPosts(String tagSlug, PostType type, int offset,
			int size, AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetTagPosts());
		url = setParameter(url, "slug", tagSlug);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getTagPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getAuthorPosts(int authorId,
			AsyncCallback<ArrayList<Post>> callback) {
		getAuthorPosts(authorId, null, -1, -1, callback);
	}

	@Override
	public void getAuthorPosts(String authorSlug,
			AsyncCallback<ArrayList<Post>> callback) {
		getAuthorPosts(authorSlug, null, -1, -1, callback);
	}

	@Override
	public void getAuthorPosts(int authorId, PostType type, int offset,
			int size, AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetAuthorPosts());
		url = setParameter(url, "id", authorId);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getAuthorPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getAuthorPosts(String authorSlug, PostType type, int offset,
			int size, AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetAuthorPosts());
		url = setParameter(url, "slug", authorSlug);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] getAuthorPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void searchPosts(String value,
			AsyncCallback<ArrayList<Post>> callback) {
		searchPosts(value, null, -1, -1, callback);
	}

	@Override
	public void searchPosts(String value, PostType type, int offset, int size,
			AsyncCallback<ArrayList<Post>> callback) {
		String url = buildOperationUrl(JsonConstant.OPERATION_NAME.GetSearchPosts());
		url = setParameter(url, "search", value);
		url = addPagingParam(url, offset, size, type);
		GWT.log("[WordPressJsonServiceAsyncImpl] searchPosts: " + url);
		getBuilder().requestObject(url, new JsonPostListCallback(callback));
	}

	@Override
	public void getDateIndex(AsyncCallback<ArrayList<DateIndex>> callback) {
		// TODO Auto-generated method stub

	}

	@Override
	public void getCategoryIndex(AsyncCallback<ArrayList<Category>> callback) {
		// TODO Auto-generated method stub

	}

	@Override
	public void getTagIndex(AsyncCallback<ArrayList<Tag>> callback) {
		// TODO Auto-generated method stub

	}

	@Override
	public void getAuthorIndex(AsyncCallback<ArrayList<Author>> callback) {
		// TODO Auto-generated method stub

	}

	@Override
	public void getPageIndex(AsyncCallback<ArrayList<Page>> callback) {
		// TODO Auto-generated method stub

	}

	protected String buildOperationUrl(String methodName) {
		return getJsonPath().concat(SLASH).concat(methodName);
	}

	protected String setParameter(String operationUrl, String name, Object value) {
		if (name == null || value == null)
			return operationUrl;

		if (!operationUrl.contains(START)) {
			operationUrl = operationUrl.concat(START);
		} else {
			operationUrl = operationUrl.concat(AND);
		}
		operationUrl = operationUrl.concat(name);
		operationUrl = operationUrl.concat(EQUAL);
		if (value instanceof Date) {
			operationUrl = operationUrl.concat(dateFormat.format((Date) value));
		} else {
			operationUrl = operationUrl.concat(String.valueOf(value));
		}
		return operationUrl;
	}

	protected String addPagingParam(String operationUrl, int offset, int size,
			PostType type) {

		operationUrl = setParameter(operationUrl, "post_type", type);

		if (size > 0) {
			operationUrl = setParameter(operationUrl, "count", size);
			if (offset >= 0) {
				operationUrl = setParameter(operationUrl, "page", ((offset / size) + 1));
			}
		}
		return operationUrl;
	}

}
